package com.sweet.util;

import com.sweet.auth.IPAuth;
import com.sweet.enums.Charset;
import com.sweet.json.JsonUtil;
import com.sweet.lang.ArrayUtil;
import com.sweet.lang.StringUtil;
import com.sweet.string.Validator;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

/**
 * web相关工具类
 *
 * @author limi 2015-10-15
 */
public final class WebUtil {
    private WebUtil() {
    }

    /**
     * 输出信息
     *
     * @param response
     * @param data     输出数据
     * @param charset  编码
     */
    public static void write(HttpServletResponse response, String data, Charset charset) throws IOException {
        // 若编码不为空，则设置
        if (charset != null) {
            response.setCharacterEncoding(charset.getCharset());
        }

        // 输出数据
        PrintWriter out = response.getWriter();
        out.write(data);
        out.flush();
        out.close();
    }

    /**
     * 定义返回值
     *
     * @param isSuccess 是否成功
     * @param message   提示消息
     * @param data      返回数据
     * @return
     */
    private static String defineReturn(boolean isSuccess, String message, Object data) {
        Map<String, Object> result = new HashMap<String, Object>(3);
        result.put("success", isSuccess);
        result.put("message", message);
        result.put("data", data);

        return JsonUtil.toJson(result);
    }

    /**
     * 定义失败返回值
     *
     * @param message 提示消息
     * @return
     */
    public static String returnFail(String message) {
        return defineReturn(false, message, null);
    }

    /**
     * 定义失败返回值
     *
     * @param message 提示消息
     * @return
     */
    public static String returnFail(String message, Object data) {
        return defineReturn(false, message, data);
    }

    /**
     * 定义成功返回值
     *
     * @param message 提示消息
     * @return
     */
    public static String returnSuccess(String message) {
        return defineReturn(true, message, null);
    }

    /**
     * 定义成功返回值
     *
     * @param message 提示消息
     * @param data    返回数据
     * @return
     */
    public static String returnSuccess(String message, Object data) {
        return defineReturn(true, message, data);
    }

    /**
     * 获取浏览器参数，转为String
     *
     * @param request
     * @param param
     * @param defaultValue
     * @return
     */
    public static String getToString(HttpServletRequest request, String param, String defaultValue) {
        return StringUtil.trim(request.getParameter(param), defaultValue);
    }

    /**
     * 获取浏览器参数，转为boolean
     *
     * @param request
     * @param param
     * @param defaultValue
     * @return
     */
    public static boolean getToBoolean(HttpServletRequest request, String param, boolean defaultValue) {
        return ConvertUtil.toBoolean(request.getParameter(param), defaultValue);
    }

    /**
     * 获取浏览器参数，转为boolean
     *
     * @param request
     * @param param
     * @return
     */
    public static boolean getToBoolean(HttpServletRequest request, String param) {
        return getToBoolean(request, param, false);
    }

    /**
     * 获取浏览器参数，转为byte
     *
     * @param request
     * @param param
     * @param defaultValue
     * @return
     */
    public static byte getToByte(HttpServletRequest request, String param, byte defaultValue) {
        return ConvertUtil.toByte(request.getParameter(param), defaultValue);
    }

    /**
     * 获取浏览器参数，转为byte
     *
     * @param request
     * @param param
     * @return
     */
    public static byte getToByte(HttpServletRequest request, String param) {
        return getToByte(request, param, (byte) 0);
    }

    /**
     * 获取浏览器参数，转为short
     *
     * @param request
     * @param param
     * @param defaultValue
     * @return
     */
    public static short getToShort(HttpServletRequest request, String param, short defaultValue) {
        return ConvertUtil.toShort(request.getParameter(param), defaultValue);
    }

    /**
     * 获取浏览器参数，转为short
     *
     * @param request
     * @param param
     * @return
     */
    public static short getToShort(HttpServletRequest request, String param) {
        return getToShort(request, param, (short) 0);
    }

    /**
     * 获取浏览器参数，转为int
     *
     * @param request
     * @param param
     * @param defaultValue
     * @return
     */
    public static int getToInt(HttpServletRequest request, String param, int defaultValue) {
        return ConvertUtil.toInt(request.getParameter(param), defaultValue);
    }

    /**
     * 获取浏览器参数，转为int
     *
     * @param request
     * @param param
     * @return
     */
    public static int getToInt(HttpServletRequest request, String param) {
        return getToInt(request, param, 0);
    }

    /**
     * 获取浏览器参数，转为long
     *
     * @param request
     * @param param
     * @param defaultValue
     * @return
     */
    public static long getToLong(HttpServletRequest request, String param, long defaultValue) {
        return ConvertUtil.toLong(request.getParameter(param), defaultValue);
    }

    /**
     * 获取浏览器参数，转为long
     *
     * @param request
     * @param param
     * @return
     */
    public static long getToLong(HttpServletRequest request, String param) {
        return getToLong(request, param, 0l);
    }

    /**
     * 获取浏览器参数，转为float
     *
     * @param request
     * @param param
     * @param defaultValue
     * @return
     */
    public static float getToFloat(HttpServletRequest request, String param, float defaultValue) {
        return ConvertUtil.toFloat(request.getParameter(param), defaultValue);
    }

    /**
     * 获取浏览器参数，转为float
     *
     * @param request
     * @param param
     * @return
     */
    public static float getToFloat(HttpServletRequest request, String param) {
        return getToFloat(request, param, 0f);
    }

    /**
     * 获取浏览器参数，转为double
     *
     * @param request
     * @param param
     * @param defaultValue
     * @return
     */
    public static double getToDouble(HttpServletRequest request, String param, double defaultValue) {
        return ConvertUtil.toDouble(request.getParameter(param), defaultValue);
    }

    /**
     * 获取浏览器参数，转为double
     *
     * @param request
     * @param param
     * @return
     */
    public static double getToDouble(HttpServletRequest request, String param) {
        return getToDouble(request, param, 0d);
    }

    /**
     * 获取项目地址<br/>
     * 如 http://127.0.0.1:8080/web
     *
     * @param request
     * @return
     */
    public static String getWebUrl(HttpServletRequest request) {
        return new StringBuilder(32).append(request.getScheme()).append("://").append(request.getServerName())
                .append(":").append(request.getServerPort()).append(request.getContextPath()).append("/").toString();
    }

    /**
     * 获取session,使用false获取，不用每次都重新定义session，提高性能
     *
     * @param request
     * @return
     */
    public static HttpSession getSession(HttpServletRequest request) {
        if (request == null) {
            return null;
        }

        // 先判断request中是否有session
        HttpSession session = request.getSession(false);

        // 如果为空，则新定义一个，不为空，则直接返回
        return session == null ? request.getSession() : session;
    }

    /**
     * 获取application
     *
     * @param request
     * @return
     */
    public static ServletContext getServletContext(HttpServletRequest request) {
        if (request == null) {
            return null;
        }

        // 先判断request中是否有session
        HttpSession session = getSession(request);

        return getServletContext(session);
    }

    /**
     * 获取application
     *
     * @param session
     * @return
     */
    public static ServletContext getServletContext(HttpSession session) {
        return session == null ? null : session.getServletContext();
    }

    /**
     * （未测试）获取IP地址，同getRemoteAddr
     *
     * @param request
     * @return
     */
//	public static String getIpAddr(HttpServletRequest request) {
//		String ip = request.getHeader("X-Real-IP");
//		if (!StringUtil.isBlank(ip) && !"unknown".equalsIgnoreCase(ip)) {
//			return ip;
//		}
//		ip = request.getHeader("X-Forwarded-For");
//		if (!StringUtil.isBlank(ip) && !"unknown".equalsIgnoreCase(ip)) {
//			// 多次反向代理后会有多个IP值，第一个为真实IP。
//			int index = ip.indexOf(',');
//			if (index != -1) {
//				return ip.substring(0, index);
//			} else {
//				return ip;
//			}
//		}
//		return request.getRemoteAddr();
//	}

    /**
     * 未知IP字符串定义
     */
    private static final String UNKNOWN_IP = "unknown";

    /**
     * 本机域名
     */
    private static final String LOCAL_HOST = "localhost";

    /**
     * 本机IPV6地址
     */
    private static final String LOCAL_IPV6 = "0:0:0:0:0:0:0:1";

    /**
     * 本机IPV4地址
     */
    private static final String LOCAL_IPV4 = "127.0.0.1";

    /**
     * 获取用户真实IP地址
     * 不使用request.getRemoteAddr()的原因是有可能用户使用了代理软件方式避免真实IP地址,
     * 可是，如果通过了多级反向代理的话，X-Forwarded-For的值并不止一个，而是一串IP值，究竟哪个才是真正的用户端的真实IP呢？
     * 答案是取X-Forwarded-For中第一个非unknown的有效IP字符串。
     * 如：X-Forwarded-For：192.168.1.110, 192.168.1.120, 192.168.1.130
     * 用户真实IP为： 192.168.1.110
     *
     * @param req
     * @return
     */
    public static String getRealIp(HttpServletRequest req) {
        //1.优先获取反向代理IP列表
        String proxyIp = req.getHeader("X-Forwarded-For");
        if (StringUtil.isNotBlank(proxyIp)) {
            //拆分IP列表
            String[] ips = StringUtil.split(proxyIp, ",");
            if (ArrayUtil.isNotEmpty(ips)) {
                for (String ip : ips) {
                    //空ip不处理
                    if (StringUtil.isBlank(ip)) {
                        continue;
                    }

                    //去掉前后空格
                    ip = StringUtil.trimToNull(ip);
                    if (UNKNOWN_IP.equalsIgnoreCase(ip) || !Validator.isIpv4(ip)) {
                        continue;
                    }

                    //非内网IP则采用
                    if (!IPAuth.isIntranetIP(ip)) {
                        return ip;
                    }
                }
            }
        }

        //获取真实IP
        String realIp = req.getHeader("x-real-ip");
        if (Validator.isIpv4(realIp)) {
            return realIp;
        }

        //最后采用自带IP获取工具
        String remoteIP = req.getRemoteAddr();
        if (remoteIP.equals(LOCAL_HOST) || remoteIP.equals(LOCAL_IPV4) || remoteIP.equals(LOCAL_IPV6)) {
            return LOCAL_IPV4;
        }

        //最后采用未知
        return Validator.isIpv4(remoteIP) ? remoteIP : UNKNOWN_IP;
    }

    /**
     * 定义页面编码
     *
     * @param charset
     * @return
     */
    public static String getPageEncode(Charset charset) {
        return new StringBuilder("<%@page contentType=\"text/html;charset=").append(charset.getCharset()).append("\"%>")
                .toString();
    }

    /**
     * 定义页面编码
     *
     * @param charset
     * @return
     */
    public static String getSimplePageEncode(Charset charset) {
        return new StringBuilder("<%@page language=\"java\" pageEncoding=\"").append(charset.getCharset())
                .append("\"%>").toString();
    }
}
